package org.jawp.persistence;

import java.net.UnknownHostException;
import java.util.LinkedList;
import java.util.List;

import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.Mongo;
import com.mongodb.MongoException;

public class ProductDAO {
	static private ProductDAO dao = null;
	private final DBCollection productCollection;
	private int currentId;

	/*************************************
	 *			Constructor
	 * @throws MongoException 
	 * @throws UnknownHostException 
	 *************************************/

	private ProductDAO() throws UnknownHostException, MongoException { //TODO change to private, add a Singleton constructor
		// connect to mongoDB (ip and port number are optional)
		Mongo mongo = new Mongo();

		// get database from MongoDB,
		// if database doesn't exists, mongoDB will create it automatically
		DB db = mongo.getDB("JAWP_DB");

		// Get collection from MongoDB, database named "Products"
		// if collection doesn't exists, mongoDB will create it automatically
		productCollection = db.getCollection("Products");

		// query the lastest id
		DBCursor cursor = productCollection.find().sort(new BasicDBObject("id", -1)).limit(1);
		// get the result
		if(cursor.size() == 0)
			currentId = 0;
		else{
			DBObject result = cursor.next();
			currentId = ((Integer)result.get("id")).intValue() + 1;
		}
	}

	public static ProductDAO getProductDAO() throws UnknownHostException, MongoException {
		if(dao == null){
			dao = new ProductDAO();
		}
		return dao;
	}

	/*************************************
	 *				Creation
	 *************************************/

	public Product createNewProduct(String name, int categoryId) { //TODO check if category exists ?
		Product product = getProductByNameAndCategory(name, categoryId);
		if(product == null){
			product = new Product(currentId, name, categoryId);

			// create a document to store key and value
			BasicDBObject document = new BasicDBObject();
			document.put("id", currentId);
			document.put("name", name);
			document.put("categoryId", categoryId);

			// save it into collection
			productCollection.insert(document);

			// increment current id
			currentId++;
		}
		return product;
	}

	/*************************************
	 *				Getter
	 *************************************/

	public List<Product> getProducts() {		 
		// search query
		BasicDBObject searchQuery = new BasicDBObject();

		// query it
		DBCursor cursor = productCollection.find(searchQuery);

		List<Product> products = new LinkedList<Product>();
		while(cursor.hasNext()){
			DBObject object = cursor.next();
			products.add(new Product((Integer)object.get("id"), (String)object.get("name"), (Integer)object.get("categoryId")));
		}

		return products;
	}

	public List<Product> getProductsByCategory(int categoryId) {		 
		// search query
		BasicDBObject searchQuery = new BasicDBObject();

		// query it
		DBCursor cursor = productCollection.find(searchQuery);
		searchQuery.put("categoryId", categoryId);

		List<Product> products = new LinkedList<Product>();
		while(cursor.hasNext()){
			DBObject object = cursor.next();
			products.add(new Product((Integer)object.get("id"), (String)object.get("name"), (Integer)object.get("categoryId")));
		}

		return products;
	}

	public Product getProductById(int id) {		 
		// search query
		BasicDBObject searchQuery = new BasicDBObject();
		searchQuery.put("id", id);

		// query it
				DBObject object = productCollection.findOne(searchQuery);

				if(object == null){
					return null;
				}

				return new Product(id, (String)object.get("name"), (Integer)object.get("categoryId"));
	}

	public Product getProductByNameAndCategory(String name, int categoryId) {		 
		// search query
		BasicDBObject searchQuery = new BasicDBObject();
		searchQuery.put("name", name);
		searchQuery.put("categoryId", categoryId);

		// query it
				DBObject object = productCollection.findOne(searchQuery);

				if(object == null){
					return null;
				}

				return new Product((Integer)object.get("id"), name, categoryId);
	}

	/*************************************
	 *				Setter
	 *************************************/

	/*************************************
	 *				Deletion
	 *************************************/

	public void deleteProduct(int id) {

		BasicDBObject searchQuery = new BasicDBObject();
		searchQuery.put("id", id);

		productCollection.remove(productCollection.findOne(searchQuery));
	}

	public void deleteProductsByCategory(int categoryId) {

		BasicDBObject searchQuery = new BasicDBObject();
		searchQuery.put("categoryId", categoryId);

		// query it
		DBCursor cursor = productCollection.find(searchQuery);

		while(cursor.hasNext()){
			productCollection.remove(cursor.next());
		}
	}
}
